home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
gnulib
/
libsrc98.zoo
/
scanf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-29
|
12KB
|
559 lines
/* Copyright (C) 1991 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA. */
/*
* adapted for atariST gcc lib
*
* NOTES: interface is different from equivalent gnuC lib function
* it was munged to match our old _scanf().
*
* if __NO_FLOAT__ is defined then the floating point stuff
* gets nuked (for iio*.olb) as per our old scanf.c.
*
* It is very important to read and understand the GNU Library General
* Public License. It specifies rights and conditions that are different
* from the GNU copyleft.
*
* ++jrb bammi@cadence.com
*/
#include <errno.h>
#include <limits.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <compiler.h>
/* the code assumes this definition, note: traditional <ctype> def
* of tolower will break the code. Ansi def should be ok.
*/
#ifdef tolower
# undef tolower
# define tolower(c) (isupper(c) ? (c)^0x20 : (c))
#endif
#ifndef __NO_FLOAT__
# define FLOATS 1
#else
# define FLOATS 0
#endif
#define TEN_MUL(X) ((((X) << 2) + (X)) << 1)
#ifdef __GNUC__
#define HAVE_LONGLONG
#define LONGLONG long long
#else
#define LONGLONG long
#endif
#define inchar() ((c = ((*get)(s))) == EOF ? EOF : (++read_in, c))
#define unchar(c) (--read_in, (*unget)(c, s))
#define conv_error() return((c == EOF || ((*unget)(c, s))), done)
#define input_error() return( done < 1 ? EOF : done )
#define memory_error() return((errno = ENOMEM), EOF)
__EXTERN long int strtol __PROTO((const char *nptr, char **endptr, int base));
__EXTERN double strtod __PROTO((const char *s, char **endptr));
/* Read formatted input from S according to the format string
FORMAT, using the argument list in ARG.
Return the number of assignments made, or -1 for an input error. */
int _scanf(s, get, unget, format, arg)
register FILE *s;
int (*get) __PROTO((FILE *));
int (*unget) __PROTO((int, FILE *));
const char *format;
va_list arg;
{
register const char *f = format;
register char fc; /* Current character of the format. */
register size_t done = 0; /* Assignments done. */
register size_t read_in = 0; /* Chars read in. */
register int c; /* Last char read. */
register int do_assign; /* Whether to do an assignment. */
register int width; /* Maximum field width. */
/* Type modifiers. */
char is_short, is_long, is_long_double;
#ifdef HAVE_LONGLONG
/* We use the `L' modifier for `long long int'. */
#define is_longlong is_long_double
#else
#define is_longlong 0
#endif
#if FLOATS
/* Status for reading F-P nums. */
char got_dot, got_e;
#endif
/* If a [...] is a [^...]. */
char not_in;
/* Base for integral numbers. */
int base;
/* Integral holding variables. */
long int num;
unsigned long int unum;
#if FLOATS
/* Floating-point holding variable. */
# ifdef __M68881__
long double fp_num;
# else
double fp_num;
# endif
#endif
/* Character-buffer pointer. */
register char *str;
/* Workspace. */
char work[256];
char *w; /* Pointer into WORK. */
if ((format == NULL) || (!*format))
{
errno = EINVAL;
input_error();
}
# define decimal ('.') /* should really come from locale stuff that we dont */
/* have as yet */
c = inchar();
/* Run through the format string. */
while (*f != '\0')
{
#if 0 /* no mb support as yet */
if (!isascii(*f))
{
/* Non-ASCII, may be a multibyte. */
int len = mblen(f, strlen(f));
if (len > 0)
{
while (len-- > 0)
if (c == EOF)
input_error();
else if (c == *f++)
(void) inchar();
else
conv_error();
continue;
}
}
#endif
fc = *f++;
if (fc != '%')
{
/* Characters other than format specs must just match. */
if (c == EOF)
input_error();
if (isspace(fc))
{
/* Whitespace characters match any amount of whitespace. */
while (isspace (c))
(void)inchar ();
continue;
}
else if (c == fc)
(void) inchar();
else
conv_error();
continue;
}
/* Check for the assignment-suppressant. */
if (*f == '*')
{
do_assign = 0;
++f;
}
else
do_assign = 1;
/* Find the maximum field width. */
width = 0;
while (isdigit(*f))
{
width *= 10;
width += *f++ - '0';
}
if (width == 0)
width = -1;
/* Check for type modifiers. */
is_short = is_long = is_long_double = 0;
while (*f == 'h' || *f == 'l' || *f == 'L')
switch (*f++)
{
case 'h':
/* int's are short int's. */
is_short = 1;
break;
case 'l':
#ifdef HAVE_LONGLONG
if (is_long)
/* A double `l' is equivalent to an `L'. */
is_longlong = 1;
else
#endif
/* int's are long int's. */
is_long = 1;
break;
case 'L':
/* double's are long double's, and int's are long long int's. */
is_long_double = 1;
break;
}
/* End of the format string? */
if (*f == '\0')
conv_error();
/* Find the conversion specifier. */
w = work;
fc = *f++;
if (fc != '[' && fc != 'c' && fc != 'n')
/* Eat whitespace. */
while (isspace(c))
(void) inchar();
switch (fc)
{
case '%': /* Must match a literal '%'. */
if (c != fc)
conv_error();
else
c = inchar();
break;
case 'n': /* Answer number of assignments done. */
if (do_assign)
*va_arg(arg, int *) = read_in - 1; /* -1 is debatable ++jrb */
break;
case 'c': /* Match characters. */
if (do_assign)
{
str = va_arg(arg, char *);
if (str == NULL)
conv_error();
}
if (c == EOF)
input_error();
if (width == -1)
width = 1;
/* mjr: */
if (do_assign) {
do
*str++ = c;
while (inchar() != EOF && --width > 0);
} else
while (inchar() != EOF && --width > 0)
;
if (do_assign)
++done;
if (c == EOF)
input_error();
break;
case 's': /* Read a string. */
if (do_assign)
{
str = va_arg(arg, char *);
if (str == NULL)
conv_error();
}
if (c == EOF)
input_error();
do
{
if (isspace(c))
break;
if (do_assign)
*str++ = c;
} while ((inchar() != EOF) && ((width > 0) ? --width != 0 : 1));
if (do_assign)
{
*str = '\0';
++done;
}
if (c == EOF)
input_error();
break;
case 'x': /* Hexadecimal integer. */
case 'X': /* Ditto. */
base = 16;
goto number;
case 'o': /* Octal integer. */
base = 8;
goto number;
case 'u': /* Decimal integer. */
case 'd': /* Ditto. */
base = 10;
goto number;
case 'i': /* Generic number. */
base = 0;
number:;
if (c == EOF)
input_error();
/* Check for a sign. */
if (c == '-' || c == '+')
{
*w++ = c;
if (width > 0)
--width;
(void) inchar();
}
/* Look for a leading indication of base. */
if (c == '0')
{
if (width > 0)
--width;
*w++ = '0';
(void) inchar();
if (tolower(c) == 'x')
{
/* one char look ahead to see if its really a lead ind */
int savec = c;
int peekc = inchar();
c = savec;
(void)unchar(peekc);
if(isxdigit(peekc))
{
if (base == 0)
base = 16;
if (base == 16)
{
if